{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    }
   },
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn.functional as F\n",
    "from torch import nn\n",
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = 'all'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# 自定义层"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "origin_pos": 0,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 不带参数的层"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "- 构造一个没有任何参数的自定义层\n",
    "    - 建立`CenteredLayer`类，要求：\n",
    "        - 从其输入中减去均值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-12-07T17:00:42.700516Z",
     "iopub.status.busy": "2022-12-07T17:00:42.700056Z",
     "iopub.status.idle": "2022-12-07T17:00:43.838393Z",
     "shell.execute_reply": "2022-12-07T17:00:43.837505Z"
    },
    "origin_pos": 2,
    "slideshow": {
     "slide_type": "fragment"
    },
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [],
   "source": [
    "class CenteredLayer(nn.Module):\n",
    "    # 继承基础层nn.Module\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "\n",
    "    def forward(self, X):\n",
    "        #减去均值\n",
    "        return X - X.mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-12-07T17:00:43.842407Z",
     "iopub.status.busy": "2022-12-07T17:00:43.841864Z",
     "iopub.status.idle": "2022-12-07T17:00:43.856009Z",
     "shell.execute_reply": "2022-12-07T17:00:43.855164Z"
    },
    "origin_pos": 7,
    "slideshow": {
     "slide_type": "fragment"
    },
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([-2., -1.,  0.,  1.,  2.])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "layer = CenteredLayer()  #实例化\n",
    "layer(torch.FloatTensor([1, 2, 3, 4, 5])) # 各个输入值减去均值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "origin_pos": 10,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "- 将层作为组件合并到更复杂的模型中\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-12-07T17:00:43.859555Z",
     "iopub.status.busy": "2022-12-07T17:00:43.859007Z",
     "iopub.status.idle": "2022-12-07T17:00:43.864905Z",
     "shell.execute_reply": "2022-12-07T17:00:43.864115Z"
    },
    "origin_pos": 12,
    "slideshow": {
     "slide_type": "fragment"
    },
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [],
   "source": [
    "net = nn.Sequential(nn.Linear(8, 128), CenteredLayer())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-12-07T17:00:43.868175Z",
     "iopub.status.busy": "2022-12-07T17:00:43.867649Z",
     "iopub.status.idle": "2022-12-07T17:00:43.873777Z",
     "shell.execute_reply": "2022-12-07T17:00:43.873018Z"
    },
    "origin_pos": 16,
    "slideshow": {
     "slide_type": "fragment"
    },
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Y的均值为0.00000'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Y = net(torch.rand(4, 8)) #检验模型运算是否正确。向该网络发送随机数据，检查均值是否为0\n",
    "f'Y的均值为{Y.mean():.5f}'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- ```python\n",
    "torch.rand(*size)\n",
    "```\n",
    "    - 生成从均匀分布$U(0,1)$中采样的随机张量\n",
    "    - `size`：整数序列，定义生成的随机张量的形状"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "- ```python\n",
    "torch.randn(*size)\n",
    "```\n",
    "    - 生成从正态分布$N(0,1)$中采样的随机张量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 带参数的层"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "origin_pos": 19,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "- 定义具有参数的层，这些参数可以通过训练进行调整"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "- 可以使用内置函数来创建参数，这些函数提供一些基本的管理功能\n",
    "    - 比如访问、初始化、共享、保存和加载模型参数\n",
    "- 这样做的好处之一是：不需要为每个自定义层编写自定义的序列化程序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-12-07T17:00:43.877216Z",
     "iopub.status.busy": "2022-12-07T17:00:43.876666Z",
     "iopub.status.idle": "2022-12-07T17:00:43.881991Z",
     "shell.execute_reply": "2022-12-07T17:00:43.881201Z"
    },
    "origin_pos": 21,
    "slideshow": {
     "slide_type": "fragment"
    },
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [],
   "source": [
    "# 实现自定义版本的全连接层\n",
    "# 该层需要输入参数：`in_units`和`units`，分别表示输入数和输出数\n",
    "\n",
    "class MyLinear(nn.Module):\n",
    "    def __init__(self, in_units, units):\n",
    "        super().__init__()\n",
    "        self.weight = nn.Parameter(torch.randn(in_units, units)) # 生成权重参数\n",
    "        self.bias = nn.Parameter(torch.randn(units,))            # 生成偏置参数\n",
    "    def forward(self, X):\n",
    "        linear = torch.matmul(X, self.weight.data) + self.bias.data\n",
    "        return F.relu(linear)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- ```python\n",
    "torch.nn.parameter.Parameter(data=None, requires_grad=True)\n",
    "```\n",
    "    - `data`：输入的张量\n",
    "    - 生成张量，并且作为块Module的参数，出现在`net.parameters()`迭代器中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-12-07T17:00:43.885384Z",
     "iopub.status.busy": "2022-12-07T17:00:43.884832Z",
     "iopub.status.idle": "2022-12-07T17:00:43.891052Z",
     "shell.execute_reply": "2022-12-07T17:00:43.890262Z"
    },
    "origin_pos": 28,
    "slideshow": {
     "slide_type": "slide"
    },
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "linear的权重为\n",
      "Parameter containing:\n",
      "tensor([[ 0.3162,  0.2361,  1.2055],\n",
      "        [ 1.8310, -1.4149,  0.1414],\n",
      "        [-0.6296, -0.0621, -0.3923],\n",
      "        [-0.3969,  2.2812, -0.1973],\n",
      "        [-1.7218,  2.4176, -3.2143]], requires_grad=True)\n"
     ]
    }
   ],
   "source": [
    "# 实例化MyLinear类并访问其模型参数\n",
    "\n",
    "linear = MyLinear(5, 3)\n",
    "\n",
    "print(f'linear的权重为\\n{linear.weight}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-12-07T17:00:43.894343Z",
     "iopub.status.busy": "2022-12-07T17:00:43.893790Z",
     "iopub.status.idle": "2022-12-07T17:00:43.899843Z",
     "shell.execute_reply": "2022-12-07T17:00:43.899055Z"
    },
    "origin_pos": 32,
    "slideshow": {
     "slide_type": "fragment"
    },
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0.0000, 2.8299, 0.4563],\n",
       "        [0.0000, 4.3097, 0.0000]])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用自定义层直接执行前向传播计算\n",
    "\n",
    "linear(torch.rand(2, 5))  # 注意输入张量的列数与linear的参数的行数保持一致"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-12-07T17:00:43.903259Z",
     "iopub.status.busy": "2022-12-07T17:00:43.902701Z",
     "iopub.status.idle": "2022-12-07T17:00:43.909376Z",
     "shell.execute_reply": "2022-12-07T17:00:43.908630Z"
    },
    "origin_pos": 37,
    "slideshow": {
     "slide_type": "fragment"
    },
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0.],\n",
       "        [0.]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用自定义层构建模型\n",
    "\n",
    "net = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1))  # 注意两个块参数形状的匹配\n",
    "\n",
    "net(torch.rand(2, 64))"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "幻灯片",
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": true,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
